package com.caishi.lkx.exam.service.impl;

import com.caishi.lkx.exam.mapper.EveryDayPracticeMapper;
import com.caishi.lkx.exam.model.EveryDayPracticeModel;
import com.caishi.lkx.exam.service.ICategoryService;
import com.caishi.lkx.exam.service.IEveryDayPracticeService;
import com.caishi.lkx.exam.service.IExamService;
import com.caishi.lkx.exam.service.IQuestionService;
import com.caishi.lkx.exam.vo.EveryDaySectionListVo;
import com.caishi.lkx.exam.vo.QuestionCollectVo;
import com.zzw.common.threadpool.SysThreadPool;
import com.zzw.common.entity.IBSDMapper;
import com.zzw.common.lock.RedissonLock;
import com.zzw.common.utils.TimeUtil;
import com.caishi.lkx.exam.ienum.type.QuestionCollectionType;

import com.caishi.lkx.exam.records.RecordsCollectType;
import com.caishi.lkx.exam.records.RecordsGetDataService;
import com.caishi.lkx.exam.records.dto.CollectionErrorAndCollectRecordDataDto;
import com.caishi.lkx.exam.records.dto.QuestionRecordsDto;

import lombok.SneakyThrows;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

@Service
public class EveryDayPracticeServiceImpl extends AbstractQuestionCollectionService<EveryDayPracticeModel, String> implements IEveryDayPracticeService {

    @Resource
    private EveryDayPracticeMapper mapper;

    @Resource
    private IQuestionService questionService;

    @Resource
    private RecordsGetDataService recordsGetDataService;

    @Resource
    private ICategoryService categoryService;

    @Resource
    private IExamService examService;

    @Override
    public IBSDMapper<EveryDayPracticeModel, String> getMapper() {
        return mapper;
    }

    @SneakyThrows
    @Override
    public QuestionCollectVo clientCollectionData(String userId, Long groupId, String id, String industryId, String examId, Long categoryId,boolean setRightAnswer) {
        Future<QuestionRecordsDto> future = SysThreadPool.submit(() -> recordsGetDataService.getQuestionRecordsResult(userId, industryId, examId, categoryId, RecordsCollectType.everyday, id));
        Future<CollectionErrorAndCollectRecordDataDto> collectFuture = SysThreadPool.submit(() -> recordsGetDataService.getCollectInCollectDataResult(userId, industryId, examId, categoryId, RecordsCollectType.everyday, id));
        var result = super.clientCollectionData(userId, groupId, id, industryId, examId, categoryId,setRightAnswer);
        coreQuestionCollectionService.safeProcess(future.get(), collectFuture.get(), result, userId, id, true);
        result.setRecordsType(RecordsCollectType.everyday);
        return result;
    }

    @Override
    QuestionCollectionType nowCollectionType() {
        return QuestionCollectionType.everyDayPractice;
    }

    @SneakyThrows
    @Override
    public EveryDayPracticeModel todayPractice(String userId, Long categoryId,LocalDate date) {
        var old = adayDetail(userId, categoryId, date);
        if (old != null) return old;
        return RedissonLock.lock(String.format("todayPractice-%s", userId), () -> {
            var old1 = adayDetail(userId, categoryId, date);
            if (old1 != null) return old1;
            EveryDayPracticeModel everyDayPracticeModel = this.selectFirst(wrappers()
                    .select(EveryDayPracticeModel::getContentMap)
                    .eq(EveryDayPracticeModel::getCategoryId, categoryId)
                    .eq(EveryDayPracticeModel::getDay, date));
            var model = new EveryDayPracticeModel();
            model.setDay(date);
            model.setCategoryId(categoryId);
            model.setUserId(userId);
            model.setContent(null != everyDayPracticeModel ? everyDayPracticeModel.getContent() : questionService.generateQuestionBlock(categoryId, null, 10, null, item -> String.format("%s-%s", "每日一练", item.getTyName()), null));
            model.setContinuityDay(getContinuity(userId));
            var m = categoryService.getById(categoryId);
            model.setName(String.format("%s-%s-每日一练-%s", examService.queryName(m.getExamId()), m.getName(), TimeUtil.DATE_TIME_FORMATTER_DAY_YMD.format(model.getDay())));
            return insert(model);
        });
    }

    @Override
    public EveryDayPracticeModel adayDetail(String userId, Long categoryId, LocalDate date) {
        return selectOne(wrappers()
                .eq(EveryDayPracticeModel::getUserId, userId)
                .eq(EveryDayPracticeModel::getCategoryId, categoryId)
                .eq(EveryDayPracticeModel::getDay, date)
        );
    }

    @Override
    public List<EveryDaySectionListVo> sectionList(String userId, Long categoryId, LocalDate startDate, LocalDate endDate) {
        if (endDate == null) {
            endDate = LocalDate.now();
        }
        if (startDate == null) {
            startDate = endDate.minusDays(7);
        }
        if (endDate.isBefore(startDate)) return Collections.emptyList();
        var map = selectList(wrappers()
                .eq(EveryDayPracticeModel::getUserId, userId)
                .eq(EveryDayPracticeModel::getCategoryId, categoryId)
                .ge(EveryDayPracticeModel::getDay, startDate)
                .le(EveryDayPracticeModel::getDay, endDate)
        ).stream().collect(Collectors.toMap(v -> TimeUtil.DATE_TIME_FORMATTER_DAY.format(v.getDay()), v -> v));
        List<EveryDaySectionListVo> result = new LinkedList<>();
        for (var i = 0; (startDate.isBefore(endDate) || startDate.equals(endDate)) && i < 100; i++) {
            var item = new EveryDaySectionListVo();
            item.setDate(startDate);
            item.setData(map.get(TimeUtil.DATE_TIME_FORMATTER_DAY.format(startDate)));
            result.add(item);
            startDate = startDate.minusDays(-1);
        }
        return result;
    }

    @Override
    public Integer getJoinCount(Long categoryId, LocalDate day) {
        return selectCount(wrappers().eq(EveryDayPracticeModel::getCategoryId, categoryId).eq(EveryDayPracticeModel::getDay, day)).intValue();
    }

    @Override
    public Integer getContinuity(String userId) {
        var today = LocalDate.now();
        var m = selectFirst(wrappers()
                .eq(EveryDayPracticeModel::getUserId, userId)
                .eq(EveryDayPracticeModel::getDay, today)
        );
        if (m == null) {
            var yesterday = today.minusDays(1);
            m = selectFirst(wrappers()
                    .eq(EveryDayPracticeModel::getUserId, userId)
                    .eq(EveryDayPracticeModel::getDay, yesterday)
            );
            if (m == null) return 1;
            return m.getContinuityDay() + 1;
        }
        return m.getContinuityDay();
    }

}
